home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-01
/
window2.zip
/
WINDOW.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-04
|
16KB
|
562 lines
/* module: window.c
* programmer: Ray L. McVay
* started: 1 Aug 84
* version: 1.2, 23 Aug 84
* version: 1.3, 14 Jun 86 as modified by Larry A. Thiel
* (I hope this version # doesn't conflict)
*
* A simple window package based on the article and programs
* by Edward Mitchell in the Jan 84 Dr. Dobb's Journal. This
* implementation uses dynamically allocated buffers for the
* window control blocks and screen save buffers.
*
* An assembly language support library called VLIB is used to
* interface the DeSmet C compiler with the IBM ROM BIOS video
* routines. VLIB will undoubtedly have to be rewritten if the
* window package is to be used with other compilers.
*
* History -
*
* 1.1 - Added style member to wcb structure, clr_window() and
* use of wn->cx for horizontal scrolling in write_text().
*
* 1.2 - Added oldx, oldy members to wcb structure and use them
* in draw_window() and remove_window().
*
* 1.3 - Added wpage member to wcb structure, functions pputch(),
* pgetch(), and pdraw_row() to window.c, and get_page() to vlib.a
* to permit windows on video pages other than 0.
* Added win_write() to provide better treatment of the window as
* a glass tty. Requires care if old method used for horizontal
* scrolling.
* Added ticker() and wticker() to window.c, get_curtyp(), kbd_ci(),
* and kbd_csts for ticker tape input with editing. ticker() may be
* used without a window. kbd_csts() is not used here but is
* available for use.
*/
#include <stdio.h>
#include <window.h>
#define HOME 0x8A /* HOME key */
#define CURLF 0x8B /* <- */
#define ENDKEY 0x8C /* END key */
#define CURRT 0x9B /* -> */
#define INSERT 0x9D /* Ins */
#define DELETE 0x9E /* Del */
/*********************
** desmet functions */
int isprint();
/*********************
** vlib1 functions */
int get_page(), get_curtyp(), getxy(), vgetc();
void gotoxy(), set_curtyp(), scrlup(), scrldn(), vputc(), vputca();
/************************************************************************
* putch(), write a character and attribute to a specific XY location on *
* the screen. The attribute is the high byte of the character. *
************************************************************************/
void pputch(x, y, c)
int x, y, c;
{
gotoxy(x, y, 0);
vputca(c, 0, 1);
}
/*************************************************
* pputch(), same as putch except uses page arg **
*************************************************/
void putch(x, y, c, page)
int x, y, c;
{
gotoxy(x, y, page);
vputca(c, page, 1);
}
/************************************************************************
* getch(), return the character and attribute at screen XY *
************************************************************************/
int getch(x, y)
int x, y;
{
gotoxy(x, y, 0);
return(vgetc(0));
}
/*************************************************
* pgetch(), same as getch except uses page arg **
*************************************************/
int pgetch(x, y, page)
int x, y;
{
gotoxy(x, y, page);
return(vgetc(page));
}
/************************************************************************
* draw_row(), output a row of one character/attribute at XY *
************************************************************************/
void draw_row(x, y, count, c)
int x, y, count,c;
{
gotoxy(x, y, 0);
vputca(c, 0, count);
}
/********************************************************
* pdraw_row(), same as draw_row except uses page arg *
********************************************************/
void pdraw_row(x, y, count, c, page)
int x, y, count,c;
{
gotoxy(x, y, page);
vputca(c, page, count);
}
/************************************************************************
* draw_window(), open a window of given size with upper left corner at *
* XY. Allocates buffers for the window control block and *
* screen save buffers. Copies overwritten screen to the *
* buffer. Draws the blank window. Returns the address of *
* the window control block or NULL if no buffer space. *
************************************************************************/
WINDOWPTR draw_window(x, y, width, height, attrib)
int x, y, width, height, attrib;
{
WINDOWPTR wn;
int tx, ty,
xend, yend;
int *tptr;
char *calloc();
if ((wn = (WINDOWPTR)calloc(1, sizeof(WINDOW))) == NULL)
return(NULL);
else if ((wn->scrnsave = (int *)calloc((width+2) * (height+2), sizeof(int))) == NULL)
{
free(wn);
return(NULL);
}
else
{
/* store parameters in window control block */
wn->wpage = get_page(); /* what video page are we on */
wn->ulx = x;
wn->uly = y;
wn->xsize = width;
wn->ysize = height;
wn->cx = 1;
wn->cy = 1;
wn->style = attrib;
attrib <<= 8; /* will make things below go quicker */
tx = getxy(wn->wpage);
wn->oldx = tx & 255;
wn->oldy = tx >> 8;
/* Copy existing text where the window will be placed */
/* to the scrnsave buffer. Obviously, a less portable */
/* routine could be much faster. */
tptr = wn->scrnsave;
xend = x + width + 2;
yend = y + height + 2;
for (ty = y; ty < yend; ty++)
{
for (tx = x; tx < xend; tx++)
*tptr++ = pgetch(tx, ty, wn->wpage);
}
/* draw the window border and clear the text area */
pputch(x, y, 0xda + attrib, wn->wpage); /* ul corner */
pdraw_row(x + 1, y, width, 0xc4 + attrib, wn->wpage); /* horiz bar */
pputch(x + width + 1, y, 0xbf + attrib, wn->wpage); /* ur corner */
yend = y + height;
for (ty = y+1; ty <= yend; ty++)
{
pputch(x, ty, 0xb3 + attrib, wn->wpage); /* draw the sides */
pputch(x+width+1, ty, 0xb3 + attrib, wn->wpage);
}
pputch(x, y + height + 1, 0xc0 + attrib, wn->wpage); /* ll corner */
pdraw_row(x + 1, y + height + 1, width, 0xc4 + attrib, wn->wpage); /* horiz bar */
pputch(x + width + 1, y + height + 1, 0xd9 + attrib, wn->wpage); /* lr corner */
clr_window(wn);
return(wn);
}
}
/************************************************************************
* remove_window(), erase the window at the window control block. *
* Must be the "top" window if overlapping windows are *
* used. "Tiled" windows could be removed randomly. *
************************************************************************/
void remove_window(wn)
WINDOWPTR wn;
{
int tx, ty,
xend, yend;
int *tptr;
/* just repaint the saved text at the appropriate location */
tptr = wn->scrnsave;
xend = wn->ulx + wn->xsize + 2;
yend = wn->uly + wn->ysize + 2;
for (ty = wn->uly; ty < yend; ty++)
{
for (tx = wn->ulx; tx < xend; tx++)
pputch(tx, ty, *tptr++, wn->wpage);
}
/* put cursor back where it was before this rude interruption */
gotoxy(wn->oldx, wn->oldy, wn->wpage);
/* then release the dynamic storage used */
free(wn->scrnsave);
free(wn);
}
/************************************************************************
* write_text(), print a string inside a window using cx, cy in WCB *
************************************************************************/
void write_text(wn, string)
WINDOWPTR wn;
char *string;
{
int tx, ty, xend;
/* first check to see if we're at the bottom of the window */
/* if we are then scroll the contents of the window up */
if (wn->cy > wn->ysize)
{
delete_row(wn, 1);
--wn->cy;
}
/* Print as much of the string as will fit in the window. *
* cx is used for relative left margin. If cx is negative then *
* the first cx characters will be removed from the string to *
* allow horizontal scrolling in the window. *
* NOTE: This obviously simple-minded technique is usable for *
* displaying predetermined messages but a more general *
* console output intercept should be used for Star-like *
* environments. */
if (wn->cx > 0)
tx = wn->ulx + wn->cx;
else
{
if (-wn->cx < strlen(string))
string -= wn->cx;
else
*string = '\0';
tx = wn->ulx + 1;
}
xend = wn->ulx + wn->xsize + 1;
ty = wn->uly + wn->cy;
while ((tx < xend) && *string)
{
gotoxy(tx++, ty, wn->wpage);
vputc(*string++, wn->wpage, 1);
}
++wn->cy; /* move the internal cursor to the next line */
}
/*****************************************************************
** Another function to write text to a window. This one uses the**
** window like a glass teletype and processes certain control **
** characters. As a result, it will not do the right thing if **
** you send it '\n' or '\r' chars after changing wn->cx to cause**
** horizontal scrolling. Tabs are NOT expanded. */
void win_text(wn,cptr)
WINDOWPTR wn;
char *cptr;
{
/* draw_window() does not position cursor AND **
** user may have moved it anyway, so start by **
** putting it where it belongs. */
gotoxy ( wn->ulx + wn->cx, wn->uly + wn->cy, wn->wpage );
while ( *cptr )
{
switch ( *cptr )
{
case '\n': wn->cy++;
if ( wn->cy > wn->ysize ) /* if past bottom of */
{ delete_row ( wn, 1 ); /* window, scroll up */
--wn->cy;
} /* pass thru to '\r' */
case '\r': wn->cx = 1;
break;
case 7: co (*cptr); /* just ring bell */
break;
case '\t': *cptr = ' '; /* replace tab & pass on*/
default: if ( wn->cx <= wn->xsize )
vputc ( *cptr, wn->wpage, 1 );
wn->cx++;
}
gotoxy ( wn->ulx + wn->cx, wn->uly + wn->cy, wn->wpage );
cptr++;
}
}
/************************************************************************
* insert_row(), insert a row of blanks by scrolling the lower portion *
* of a window down *
************************************************************************/
void insert_row(wn, row)
WINDOWPTR wn;
int row;
{
int scrlwn[4];
/* calculate corners of the scrolling window */
scrlwn[0] = wn->ulx + 1; /* ulx */
scrlwn[1] = wn->uly + row; /* uly */
scrlwn[2] = wn->ulx + wn->xsize; /* lrx */
scrlwn[3] = wn->uly + wn->ysize; /* lry */
scrldn(scrlwn, 1, wn->style);
}
/************************************************************************
* delete_row(), delete a row by scrolling the lower portion of a window *
* up and inserting a row of blanks at the bottom row *
************************************************************************/
void delete_row(wn, row)
WINDOWPTR wn;
int row;
{
int scrlwn[4];
/* calculate corners of the scrolling window */
scrlwn[0] = wn->ulx + 1; /* ulx */
scrlwn[1] = wn->uly + row; /* uly */
scrlwn[2] = wn->ulx + wn->xsize; /* lrx */
scrlwn[3] = wn->uly + wn->ysize; /* lry */
scrlup(scrlwn, 1, wn->style);
}
/************************************************************************
* clr_window(), clear the "active" part of a window and "home" internal *
* text cursor *
************************************************************************/
void clr_window(wn)
WINDOWPTR wn;
{
int scrlwn[4];
/* calculate corners of the scrolling window */
scrlwn[0] = wn->ulx + 1; /* ulx */
scrlwn[1] = wn->uly + 1; /* uly */
scrlwn[2] = wn->ulx + wn->xsize; /* lrx */
scrlwn[3] = wn->uly + wn->ysize; /* lry */
scrlup(scrlwn, 0, wn->style);
wn->cx = 1;
wn->cy = 1;
}
/*********************************************************************
** Operator edit of null terminated string in buffer at ptr. Buffer **
** size must be > max bytes and function will allow result to be up **
** to max bytes in length. Function may be called with an empty **
** string for entry of all new data. Function will use width chars **
** at row, col of video page page to display a ticker tape of the **
** working string. Function returns the length of the result. */
int ticker(row,col,ptr,max,width,page)
int row, col, max, width;
char *ptr;
{
int i, j, toffset, tcur, spos, count, key, repl;
int rwright, rwleft, repl, vlines, oldcbeg, oldcend;
char *cptr, *lptr;
i = get_curtyp();
oldcbeg = i >> 8;
oldcend = i & 255;
vlines = ( get_mode() == 7 ) ? 13 : 7;
toffset = tcur = spos = count = repl = 0;
i = ( repl ) ? vlines - 1 : 0;
set_curtyp ( i, vlines );
gotoxy ( col, row, page );
vputc ( ' ', page, width );
cptr = ptr;
while ( *cptr++ )
count++;
rwleft = 0;
rwright = 1;
while ( 1 )
{ if ( rwleft )
{ for ( i=0, cptr = ptr + toffset; i < (width-1); i++ )
{ gotoxy ( col + i, row, page );
vputc ( *cptr++, page, 1 );
}
rwleft = 0;
}
if ( rwright )
{ i = tcur;
cptr = ptr + spos;
while ( i < width )
{ gotoxy ( col + i++, row, page );
if ( *cptr )
{ vputc ( *cptr++, page, 1 );
}
else
{ vputc ( ' ', page, 1 );
break;
}
}
rwright = 0;
}
gotoxy ( col + tcur, row, page );
key = kbd_ci();
if ( isprint (key) )
goto prt_char; /* not control key */
if ( key == 8 )
{ if ( spos < 1 ) /* backspace */
goto bad_key;
tcur--;
spos--;
key = DELETE;
}
if ( key == 7 )
key = DELETE; /* change ^G to DELETE */
if ( key == DELETE )
{ if ( spos >= count ) /* Delete key */
goto bad_key;
cptr = ptr + spos;
lptr = cptr + 1;
while ( *cptr )
*cptr++ = *lptr++;
count--;
rwright = 1;
}
if ( (key == CURLF) || (key == 19) )
{ if ( spos < 1 ) /* Left arrow or ^S */
goto bad_key;
tcur--;
}
if ( (key == CURRT) || (key == 4) )
{ if ( spos >= count ) /* Right arrow or ^D */
goto bad_key;
tcur++;
}
if ( (key == 22) || (key == INSERT) )
{ repl = -1 - repl; /* Insert key or ^V */
i = ( repl ) ? vlines - 1 : 0;
set_curtyp ( i, vlines );
}
if ( key == HOME )
tcur = -toffset; /* Home key */
if ( key == ENDKEY )
tcur = count - toffset; /* End Key */
if ( key == '\r' )
{ set_curtyp ( oldcbeg, oldcend );
return ( count ); /* Return key */
}
goto cur_chk;
prt_char:
if ( spos >= max )
goto bad_key; /* at end of full string*/
if ( repl && (spos < count) )
goto repl_char; /* replace mode */
if ( count >= max )
goto bad_key; /* no room to insert key*/
i = ++count - spos;
cptr = ptr + count;
lptr = cptr - 1;
while ( i-- ) /* make room for key */
*cptr-- = *lptr--;
rwright = 1;
repl_char:
cptr = ptr + spos;
*cptr = key;
vputc ( *cptr, page, 1 );
tcur++;
cur_chk:
if ( tcur < 0 )
{ toffset += tcur;
tcur = 0;
rwright = 1;
}
if ( tcur >= width )
{ toffset += tcur - width + 1;
tcur = width - 1;
if ( (toffset + tcur) >= max )
toffset--;
rwleft = 1;
rwright = 1;
}
bad_key:
spos = toffset + tcur;
}
}
/*****************************************
** edit string (see ticker()) in window */
int wticker(wn,ptr,max,width)
WINDOWPTR wn;
char *ptr;
int max, width;
{
int i, row, col, page;
row = wn->uly + wn->cy;
col = wn->ulx + wn->cx;
page = wn->wpage;
i = wn->xsize - wn->cx + 1;
if ( (i < width) && (i > 0) )
width = i;
return ( ticker ( row, col, ptr, max, width, page ) );
}